package com.djzhou.gmms.dao.base.impl;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.djzhou.gmms.dao.base.BaseDAO;
import com.djzhou.gmms.model.entity.Entity;
import com.djzhou.gmms.model.entity.PageBean;
import com.djzhou.util.TypeConvert;

public class BackupDAOImpl <T extends Entity> extends HibernateDaoSupport implements BaseDAO<T>{

	@CacheEvict(value = "data", allEntries = true)  
	public void delete(T t) {
		getHibernateTemplate().delete(t);
	}

	@CacheEvict(value = "data", allEntries = true)
	public int delete(String hql, Object... params) throws DataAccessException{
		return update(hql, params);
	}

	@CacheEvict(value = "data", allEntries = true)  
	public void delete(Class<T> entityClass,Integer id) {
		getHibernateTemplate().delete(queryByID(entityClass,id));
	}

	@CacheEvict(value = "data", allEntries = true)  
	public void delete(Class<T> entityClass,String id) {
		getHibernateTemplate().delete(queryByID(entityClass,id));		
	}

	@CacheEvict(value = "data", allEntries = true)  
	public void insert(T t) {
		getHibernateTemplate().save(t);
	}

	@SuppressWarnings("unchecked")
	@Cacheable(value="data")
	public List<T> query(String hql, Object... params) {
		return getHibernateTemplate().find(hql,params);
	}

	@Cacheable(value="data")
	public T queryByID(Class<T> entityClass,String id) {
		return (T) getHibernateTemplate().get(entityClass, id);
	}

	@Cacheable(value="data")
	public T queryByID(Class<T> entityClass,Integer id) {
		return (T) getHibernateTemplate().get(entityClass, id);
	}
	
	@CacheEvict(value = "data", allEntries = true)  
	public void update(T t) {
		getHibernateTemplate().update(t);
	}
	
	@CacheEvict(value = "data", allEntries = true)  
	public int update(String hql, Object... params) {
		Session session=getHibernateTemplate().getSessionFactory().getCurrentSession();
		try{
			Query q=session.createQuery(hql);
			if(params!=null && params.length!=0){
				for(int i=0;i<params.length;i++){
					q.setParameter(i,params[i]);
				}
			}
			int result = q.executeUpdate();
			return result;
		}catch (DataAccessException e) {
			throw e;
		}finally{
		}
	}
	
	@CacheEvict(value = "data", allEntries = true)  
	public int updateForSpring(String hql, Object... params) {
		Session session=getHibernateTemplate().getSessionFactory().getCurrentSession();
		try{
			Query q=session.createQuery(hql);
			if(params!=null && params.length!=0){
				for(int i=0;i<params.length;i++){
					q.setParameter(i,params[i]);
				}
			}
			int result = q.executeUpdate();
			return result;
		}catch (DataAccessException e) {
			throw e;
		}finally{
		}
	}
	
	@Cacheable(value="data")
	public Boolean isEmpty(Class<T> entityClass,Integer id) {
		T t=(T)getHibernateTemplate().get(entityClass, id);
		if(t==null) return true;
		return false;
	}
	@Cacheable(value="data")
	public Boolean isEmpty(Class<T> entityClass,String id) {
		T t=(T)getHibernateTemplate().get(entityClass, id);
		if(t==null) return true;
		return false;
	}

	@SuppressWarnings("unchecked")
	@Cacheable(value="data")
	public Boolean isEmpty(String hql, Object... params) {
		List<T> list=getHibernateTemplate().find(hql,params);
		if(list==null)
			return true;
		if(list.size()==0)
			return true;
		return false;
	}
	@SuppressWarnings("unchecked")
	@Cacheable(value="data")
	public PageBean<T> selectByPage(final String hql,int pageSize, int currentPage)
			throws DataAccessException {
		/**
		 * 总记录数
		 */
		int allRow = 0;
		try{
			String countHql = "select count(*) ";
			if(hql!=null && hql.length()>6 && hql.substring(0, 6).equals("select"))
				countHql+=hql.substring(hql.lastIndexOf("from"));
			else
				countHql+=hql;
			int index = countHql.lastIndexOf("order by");
			if(index!=-1){
				countHql=countHql.substring(0,countHql.lastIndexOf("order by"));
			}
			List tempList = super.getHibernateTemplate().find(countHql);
			allRow = tempList!=null && tempList.size()==1 ? ((Long)tempList.get(0)).intValue():0;
		}catch (Exception e) {
			allRow = super.getHibernateTemplate().find(hql).size();
		}
		
		/**
		 * 总页数
		 */
		int totalPage = PageBean.countTotalPage(pageSize, allRow);
		/**
		 * 当前页开始记录
		 */
		final int offset = PageBean.countOffset(pageSize, currentPage);
		
		/**
		 * 每页记录数
		 */
		final int length = pageSize;
		/**
		 * 计算当前页
		 */
		final int page = PageBean.countCurrentPage(currentPage);
		/**
		 * 数据列表
		 */
		List list = super.getHibernateTemplate().executeFind(new HibernateCallback(){
			public Object doInHibernate(Session session) throws HibernateException,SQLException{ 
				Query query = session.createQuery(hql);
				query.setFirstResult(offset);
				query.setMaxResults(length);
				List list = query.list();
				return list;
			}
		});

		//把分页信息保存到PageBean中
		PageBean pageBean = new PageBean();
		pageBean.setPageSize(pageSize);
		pageBean.setCurrentPage(page); 
		pageBean.setAllRow(allRow); 
		pageBean.setTotalPage(totalPage); 
		pageBean.setList(list); 
		pageBean.init();
		
		return pageBean;
	}

	@Cacheable(value="data")
	public PageBean<T> selectByPage(final String hql,Map<String, Object> filterMap,
			int pageSize, int currentPage) {
		return null;
	}
	
	@CacheEvict(value = "data", allEntries = true)  
	public void merge(T t) {
		getHibernateTemplate().merge(t);
		
	}

	@SuppressWarnings("unchecked")
	@Cacheable(value="data")
	public int execSqlQuery(final String sql,final Object... params) {
		List<Object> list=getHibernateTemplate().executeFind(new HibernateCallback() {
			public List<Object> doInHibernate(Session session) throws HibernateException,SQLException {
				SQLQuery q=session.createSQLQuery(sql);
				for(int i=0;i<params.length;i++){
					q.setParameter(i,params[i]);
				}
				return q.list();
			}
		});
		Integer count=Integer.parseInt(list.get(0).toString());
		return count;
	}
	
	@SuppressWarnings("unchecked")
	@CacheEvict(value = "data", allEntries = true)  
	public void execSql(final String sql, final Object... params) {
		getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException,SQLException {
				SQLQuery q=session.createSQLQuery(sql);
				for(int i=0;i<params.length;i++){
					q.setParameter(i,params[i]);
				}
				q.executeUpdate();
				return null;
			}
		});
	}
	@SuppressWarnings("unchecked")
	@Cacheable(value="data")
	public List<T> searchSql(final Class<T> c,final String sql,final int firstResult,final int maxResult,final Object... params) {
		List<T> list=getHibernateTemplate().executeFind(new HibernateCallback() {
			public List<T> doInHibernate(Session session) throws HibernateException,SQLException {
				Query q=session.createSQLQuery(sql).addEntity(c);
				if(params!=null && params.length>0){
					for(int i=0;i<params.length;i++){
						q.setParameter(i,params[i]);
					}
				}
				q.setFirstResult(firstResult).setMaxResults(maxResult);
				List<T> list=q.list();
				return list;
			}
		});
		return list;
	}
	@Cacheable(value="data")
	public <E> List<E> executeSelect(Class<E> c,int fristResult,int pageSize,String sql,Object...params) throws Exception{
		return execute(c,null,fristResult,pageSize,sql,params);
	}
	@Cacheable(value="data")
	public Object searchSql(String sql,String column) throws Exception{
		PreparedStatement stmt=null;
		Connection connection=null;
		ResultSet rs=null;
		connection=SessionFactoryUtils.getDataSource(getHibernateTemplate().getSessionFactory()).getConnection();
		stmt=connection.prepareStatement(sql);
		rs=stmt.executeQuery();
		Object object=null;
		if(rs.next()){
			object=rs.getObject(column);
		}
		rs.close();
		stmt.close();
		connection.close();
		return object;
	}
	
	/**
	 * 
	 * 执行SQL语句
	 * @param <E> 
	 * @param c 返回结合体类型
	 * @param resource 返回集合源类型
	 * @param fristResult 开始记录 从1开始
	 * @param pageSize 每页显示多少条
	 * @param sql 要执行的SQL语句
	 * @param params 参数
	 * @return
	 * @throws Exception
	 *
	 */
	@Cacheable(value="data")
	private <E> List<E> execute(Class<E> c, Map<String,Integer> resource,int fristResult, int pageSize, String sql, Object... params) throws Exception{
		PreparedStatement statement=null;
		Map<String,String> colum=new HashMap<String,String>();
		Connection conn=null;
		ResultSet resultSet=null;
		int rowCount=0;
		conn=SessionFactoryUtils.getDataSource(getHibernateTemplate().getSessionFactory()).getConnection();
		List<E> list=null;
		E newInstance=null;
		statement=conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
		if(params!=null){
			for (int i = 0; i < params.length; i++) {
				statement.setObject(i+1, params[i]);
			}
		}
		resultSet=statement.executeQuery();
		resultSet.last();
		rowCount=resultSet.getRow();
		if(rowCount<fristResult){
			resultSet.close();
			statement.close();
			conn.close();
			return null;
		}
		if(fristResult==1){
			resultSet.beforeFirst();
		}else{
			resultSet.absolute(fristResult-1);
		}
		Method[] methods=c.getDeclaredMethods();
		ResultSetMetaData rsm=resultSet.getMetaData();
		for(int col=1;col<rsm.getColumnCount()+1;col++){
			colum.put(rsm.getColumnName(col).toLowerCase(), rsm.getColumnName(col).toLowerCase());
		}
		while (resultSet.next()) {
			newInstance=c.newInstance();
			for (Method method : methods) {
				if(!(method.getName().substring(0,3).equalsIgnoreCase("set")))//判断是否是SET方法
					continue;
				if(colum.get(method.getName().substring(3).toLowerCase())==null)//判断此列是否存在
					continue;
				Object object=resultSet.getObject(method.getName().substring(3));//如果存在则取出当前列值
				if(object==null)
					continue;
				
				if(resource!=null){
					Integer type=resource.get(method.getName().substring(3).toLowerCase());
					if(type==null)
						method.invoke(newInstance, object);
					else
						method.invoke(newInstance,TypeConvert.convert(object,type));
				}else{
					method.invoke(newInstance, object);
				}
				/*if(object.getClass().toString().equals("class java.math.BigDecimal")){
					method.invoke(newInstance, Double.parseDouble(object.toString()));
				}else{
					method.invoke(newInstance, object);
				}*/
				
			}
			if(list==null){
				list = new ArrayList<E>();
			}
			list.add(newInstance);
			if(list.size()==pageSize){
				break;
			}
		}
		resultSet.close();
		statement.close();
		conn.close();
		return list;
	}
	@Cacheable(value="data")
	public Query getQuery(String hql) throws Exception {
		return getSession().createSQLQuery(hql);
	}

	@Cacheable(value="data")
	public int getCount(String hql,Object ... values) throws Exception {
		return getHibernateTemplate().find(hql, values).size();
	}

}
